package com.uinnova.product.eam.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.binary.core.util.BinaryUtils;
import com.binary.jdbc.Page;
import com.uinnova.product.eam.base.exception.ServerException;
import com.uinnova.product.eam.base.util.EamUtil;
import com.uinnova.product.eam.comm.bean.CatalogDto;
import com.uinnova.product.eam.comm.dto.ListClassConfig;
import com.uinnova.product.eam.comm.model.es.AppSquareConfig;
import com.uinnova.product.eam.comm.model.es.CEamListing;
import com.uinnova.product.eam.comm.model.es.EamListing;
import com.uinnova.product.eam.model.AppSquareConfigBo;
import com.uinnova.product.eam.model.DirListConfigDto;
import com.uinnova.product.eam.model.ListCondition;
import com.uinnova.product.eam.model.ListDto;
import com.uinnova.product.eam.service.AppSquareConfigSvc;
import com.uinnova.product.eam.service.IEamListingSvc;
import com.uinnova.product.eam.service.es.AppSquareConfigDao;
import com.uinnova.product.eam.service.es.EamListingDao;
import com.uinnova.product.eam.service.es.IamsESCIDesignSvc;
import com.uinnova.product.vmdb.comm.model.ci.CCcCiClass;
import com.uinnova.product.vmdb.comm.model.ci.CcCiAttrDef;
import com.uinnova.product.vmdb.comm.util.PropertyType;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiClassInfo;
import com.uino.api.client.cmdb.ICIClassApiSvc;
import com.uino.api.client.cmdb.IDataSetApiSvc;
import com.uino.bean.cmdb.business.dataset.DataSetExeResultSheetPage;
import com.uino.bean.permission.base.SysUser;
import com.uino.dao.util.ESUtil;
import com.uino.util.sys.SysUtil;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 王春蕾
 */
@Service
@Slf4j
public class EamListingSvcImpl implements IEamListingSvc {

    @Resource
    private EamListingDao listingDao;

    @Resource
    private AppSquareConfigDao squareConfigDao;

    @Resource
    private IDataSetApiSvc dataSetApiSvc;

    @Resource
    private IamsESCIDesignSvc esCiSvc;
    @Resource
    private ICIClassApiSvc ciClassApiSvc;

    @Resource
    private AppSquareConfigSvc configSvc;

    @Override
    public Long saveOrUpdate(CEamListing eamList) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.termQuery("name.keyword", eamList.getName().trim()));
        boolQueryBuilder.must(QueryBuilders.termQuery("dataStatus", 1));
        if (!BinaryUtils.isEmpty(eamList.getId())) {
            boolQueryBuilder.mustNot(QueryBuilders.termQuery("id", eamList.getId()));
        }
        EamListing record = listingDao.selectOne(boolQueryBuilder);
        if (!BinaryUtils.isEmpty(record)) {
            throw new ServerException("清单类型名称已存在");
        }
        EamListing listing = EamUtil.copy(eamList, EamListing.class);
        if(BinaryUtils.isEmpty(eamList.getId())){
            long uuid = ESUtil.getUUID();
            listing.setId(uuid);
            //数据状态 1 表示正常
            listing.setDataStatus(1);
            //添加的时候默认是未发布状态 0
            listing.setReleaseState(0);
        }
        return listingDao.saveOrUpdate(listing);
    }


    @Override
    public List<EamListing> queryLists(ListCondition dto) {
        String nameKey = dto.getLike();
        Integer releaseState = dto.getReleaseState();
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("dataStatus", 1));
        if (!StringUtils.isEmpty(nameKey)) {
            query.must(QueryBuilders.wildcardQuery("name.keyword",  "*" + nameKey.trim() + "*"));
        }
        if (!StringUtils.isEmpty(releaseState)) {
            query.must(QueryBuilders.termQuery("releaseState", releaseState));
        }
        List<SortBuilder<?>> sorts = new ArrayList<>();
        sorts.add(SortBuilders.fieldSort("modifyTime").order(SortOrder.DESC));
        Page<EamListing> pageList = listingDao.getSortListByQuery(1, 10000, query, sorts);
        return pageList.getData();
    }

    @Override
    public EamListing queryListById(Long id) {
        CEamListing cEamList = new CEamListing();
        cEamList.setId(id);
        cEamList.setDataStatus(1);
        List<EamListing> byCdt = listingDao.getListByCdt(cEamList);
        if(BinaryUtils.isEmpty(byCdt)){
            return null;
        }

        return byCdt.get(0);
    }

    @Override
    public String deleteListing(Long id) {
        //校验清单是否被基础操作-卡片引用，
        AppSquareConfigBo basicBo = new AppSquareConfigBo();
        //资产清单类型=4
        basicBo.setClassification("4");
        List<AppSquareConfig> listInfo = configSvc.getListInfo(basicBo);
        if(!BinaryUtils.isEmpty(listInfo)){
            for (AppSquareConfig config : listInfo) {
                String configure = config.getConfigure();
                if(!BinaryUtils.isEmpty(configure)){
                    List<DirListConfigDto> listConfig = JSON.parseArray(configure, DirListConfigDto.class);
                    //收集所有的清单信息
                    List<ListDto> collect = listConfig.stream().map(DirListConfigDto::getData).flatMap(Collection::stream).collect(Collectors.toList());
                    List<Long> ids = collect.stream().map(ListDto::getId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
                    if(!BinaryUtils.isEmpty(ids) && ids.contains(id)){
                        return "该清单类型已被资产清单引用，请检查！";
                    }
                }
            }
        }
        EamListing eamList = new EamListing();
        eamList.setId(id);
        eamList.setDataStatus(0);
        listingDao.saveOrUpdate(eamList);
        return null;
    }

    @Override
    public Long releaseListing(Long id, Integer releaseState) {
        CEamListing eamList = new CEamListing();
        eamList.setId(id);
        eamList.setDataStatus(1);
        List<EamListing> listByCdt = listingDao.getListByCdt(eamList);
        if(BinaryUtils.isEmpty(listByCdt)){
            throw new ServerException("当前清单数据已被删除，请检查");
        }
        EamListing eamListing = listByCdt.get(0);
        eamListing.setReleaseState(releaseState);
        listingDao.saveOrUpdate(eamListing);
        return null;
    }

    @Override
    public List<DirListConfigDto> dataAssetsList(Long cardId) {
        AppSquareConfig configDto = new AppSquareConfig();
        configDto.setId(cardId);
        configDto.setClassification(String.valueOf(4));
        List<AppSquareConfig> cardList = squareConfigDao.getListByCdt(configDto);
        if(BinaryUtils.isEmpty(cardList)){
            return new ArrayList<>();
        }
        AppSquareConfig config = cardList.get(0);
        List<CatalogDto> catalogList = config.getCatalogList();
        //获取清单卡片配置项
        String stringConfig = config.getConfigure();
        int length = stringConfig.length();
        log.info("清单卡片配置项::"+length);
        //只有一级目录，没有二级目录
        if(!BinaryUtils.isEmpty(catalogList) && stringConfig.contentEquals("{}")){
            List<DirListConfigDto> configure = new ArrayList<>();
            for (CatalogDto catalogDto : catalogList) {
                DirListConfigDto config1 = new DirListConfigDto();
                config1.setName(catalogDto.getCatalogName());
                config1.setCardName(config.getCardName());
                configure.add(config1);
            }
            return configure;
        }
        //没有一级目录，也没有二级目录
        if(stringConfig.contentEquals("{}")){
            return new ArrayList<>();
        }
        //有/没有一级目录，有二级目录
        List<DirListConfigDto> configure = JSON.parseArray(stringConfig, DirListConfigDto.class);
        //所有清单名称
        List<String> listNames = configure.stream().map(DirListConfigDto::getData).flatMap(Collection::stream)
                .map(ListDto::getName).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        BoolQueryBuilder listQuery = new BoolQueryBuilder();
        listQuery.must(QueryBuilders.termsQuery("name.keyword",listNames));
        List<EamListing> listInfo = listingDao.getListByQuery(listQuery);
        if(BinaryUtils.isEmpty(listInfo)){
            return new ArrayList<>();
        }
        //目前清单数据应该只有几个，几次循环，考虑优化；
        Map<String ,Integer> countMap = new HashMap<>(16);
        for (EamListing list : listInfo) {
            Long id = list.getDataSetId();
            JSONObject dataSetById = dataSetApiSvc.findDataSetById(id);
            String classId = dataSetById.get("classId").toString();
            BoolQueryBuilder query = new BoolQueryBuilder();
            query.must(QueryBuilders.termQuery("classId", Long.valueOf(classId)));
            long count = esCiSvc.countByCondition(query);
            //key = 清单名称，value= 清单中的数据集中的根节点的ci个数的count
            countMap.put(list.getName(), Math.toIntExact(count));
        }
        //二级目录不为空
        if(!BinaryUtils.isEmpty(configure)){
            for (DirListConfigDto listConfigDto : configure) {
                listConfigDto.setCardName(config.getCardName());
                for (ListDto conList : listConfigDto.getData()) {
                    String name = conList.getName();
                    conList.setCount(countMap.get(name));
                }
            }
        }
        return configure;
    }



    @Override
    public DataSetExeResultSheetPage getListingData(Long id, String like, int pageNum, int pageSize) {
        EamListing listing = queryListById(id);
        DataSetExeResultSheetPage result = new DataSetExeResultSheetPage();
        if(BinaryUtils.isEmpty(listing) || BinaryUtils.isEmpty(listing.getDataSetId())){
            return result;
        }
        Long dataSetId = listing.getDataSetId();
        JSONObject dataSet = dataSetApiSvc.findDataSetById(dataSetId);
        if(BinaryUtils.isEmpty(dataSet) || BinaryUtils.isEmpty(dataSet.get("nodes"))){
            return result;
        }
        Map<String, Map<String, ListClassConfig>> headConfig = listing.getHeadConfig();
        SysUser user = SysUtil.getCurrentUserInfo();
        List<Map<String, Object>> sheets = dataSetApiSvc.getDataSetSheets(dataSetId);
        if(BinaryUtils.isEmpty(sheets)){
            return result;
        }
        String sheetId = sheets.get(0).get("name").toString();
        JSONArray condition = new JSONArray();
        if(!BinaryUtils.isEmpty(like)){
            Map<String, Object> map = new HashMap<>(2);
            map.put("type", PropertyType.VARCHAR.getValue());
            map.put("value", like);
            condition.add(map);
        }
        result = dataSetApiSvc.queryDataSetResultBySheet(user.getDomainId(), dataSetId,
                sheetId, pageNum, pageSize, null, false, condition, user.getLoginCode());
        List<String> keyList = result.getHeaders().stream().map(each -> each.get("attrKey")).collect(Collectors.toList());
        for (Map<String, String> header : result.getHeaders()) {
            String classId = header.get("classId");
            String attrName = header.get("attrName");
            String className = header.get("className");
            if(BinaryUtils.isEmpty(className)){
                continue;
            }
            header.put("attrName", attrName+"【"+className+"】");
            Map<String, ListClassConfig> attrConfig = headConfig.get(className);
            if(BinaryUtils.isEmpty(attrConfig)){
                continue;
            }
            ListClassConfig config = attrConfig.get(attrName);
            if(BinaryUtils.isEmpty(config)){
                continue;
            }
            header.put("sort", config.getSort().toString());
            header.put("search", config.getSearch().toString());
            header.put("screening", config.getScreening().toString());
        }
        return result;
    }

    @Override
    public List<CcCiClassInfo> getClassByDataSet(Long id) {
        JSONObject dataSet = dataSetApiSvc.findDataSetById(id);
        if(BinaryUtils.isEmpty(dataSet)){
            return Collections.emptyList();
        }
        JSONArray nodes = dataSet.getJSONArray("nodes");
        if(BinaryUtils.isEmpty(nodes)){
            return Collections.emptyList();
        }
        Set<Long> classIds = new HashSet<>();
        List<JSONObject> nodeList = nodes.toJavaList(JSONObject.class);
        Map<Long, List<CcCiAttrDef>> attrMap = new HashMap<>(nodeList.size());
        for (JSONObject node : nodeList) {
            Long classId = node.getLong("classId");
            if(BinaryUtils.isEmpty(classId)){
                continue;
            }
            classIds.add(classId);
            String nodeReturns = node.getString("nodeReturns");
            List<CcCiAttrDef> attrs = JSON.parseArray(nodeReturns, CcCiAttrDef.class);
            attrMap.put(classId, attrs);
        }
        CCcCiClass cdt = new CCcCiClass();
        cdt.setIds(classIds.toArray(new Long[]{}));
        List<CcCiClassInfo> classList = ciClassApiSvc.queryClassByCdt(cdt);
        if(BinaryUtils.isEmpty(classList)){
            return Collections.emptyList();
        }
        for (CcCiClassInfo each : classList) {
            each.setAttrDefs(attrMap.get(each.getCiClass().getId()));
        }
        return classList;
    }


}
